﻿using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using Framework;
using System.Text.RegularExpressions;
using System;
using Newtonsoft.Json;

namespace FrameworkEditor
{
    public static class FilterCommonAbTool
    {
        public static string abCommonSettingsPath = FrameworkSettings.ProjRootDir + "/Editor/Settings/abcommonsettings.json";
        public static string abCommonResultPath = FrameworkSettings.ProjRootDir + "/Editor/Settings/abcommonresult.json";
        public static string abCommonResultTestPath = FrameworkSettings.ProjRootDir + "/Editor/Settings/abcommonresultTest.json";
        public static string frameworkAbCommonSettingsPath = FrameworkSettings.FrameworkRootDir + "/Editor/Settings/abcommonsettings.json";
        public static void Build(bool useAddMode = true)
        {
            if (!FileHelper.IsFileExists(abCommonSettingsPath))
            {
                Debug.LogWarning("项目下没有配置抽取共用资源构建策略,拷贝框架中的模板!");
                FileHelper.WriteTextToPath(abCommonSettingsPath, FileHelper.ReadText(frameworkAbCommonSettingsPath));
                AssetDatabase.Refresh();
            }
            HashSet<string> assetNameInPreResult = new HashSet<string>();
            Dictionary<string, int> dirAbMaxIndexTab = new Dictionary<string, int>();
            Dictionary<string, object> abNameAssetsTab = null;

            if (useAddMode)
            {
                string preResultJson = FileHelper.ReadText(abCommonResultPath);
                if (!string.IsNullOrEmpty(preResultJson))
                {
                    abNameAssetsTab = JsonHelper.DerializeAsDic(preResultJson);
                    foreach (var abName in abNameAssetsTab.Keys)
                    {
                        int lastIndexOfSplit = abName.LastIndexOf("_");

                        string dirName = abName.Substring(0, lastIndexOfSplit);
                        string maxCountStr = abName.Substring(lastIndexOfSplit + 1, abName.Length - lastIndexOfSplit - 1);

                        // Debug.LogWarning($"dirName:{dirName} maxCountStr:{maxCountStr}");
                        int maxCount = JsonHelper.GetJsonInt(maxCountStr);
                        if (dirAbMaxIndexTab.ContainsKey(dirName))
                        {
                            if (dirAbMaxIndexTab[dirName] < maxCount)
                            {
                                dirAbMaxIndexTab[dirName] = maxCount;
                            }
                        }
                        else
                        {
                            dirAbMaxIndexTab[dirName] = maxCount;
                        }
                        Dictionary<string, object> oneAbInfo = (Dictionary<string, object>)abNameAssetsTab[abName];
                        foreach (var assetName in oneAbInfo.Keys)
                        {
                            if (assetNameInPreResult.Contains(assetName))
                            {
                                Debug.LogError($"assetName={assetName} is more than one!!");
                            }
                            assetNameInPreResult.Add(assetName);
                        }
                    }
                }
            }


            string settingText = FileHelper.ReadText(abCommonSettingsPath);
            if (string.IsNullOrEmpty(settingText))
            {
                Debug.LogError("FilterCommonAb.Build, settingText is null!");
                return;
            }
            // EditorUtility.DisplayProgressBar("刷新冗余ab配置", "正在扫描构建配置，请稍候！", 0.01f);
            Debug.Log("settingText = " + settingText);
            Dictionary<string, object> allSettingsTab = JsonHelper.DerializeAsDic(settingText);
            Dictionary<string, object> abSettingsDic = (Dictionary<string, object>)allSettingsTab["common"];
            Dictionary<string, Dictionary<string, string[]>> filterResultDic = new Dictionary<string, Dictionary<string, string[]>>();
            Dictionary<string, Dictionary<string, string>> filterResultDic1 = new Dictionary<string, Dictionary<string, string>>();
            //把原有的配置加入
            if (useAddMode)
            {
                foreach (var kvp in abNameAssetsTab)
                {
                    Dictionary<string, object> oneAbInfo = (Dictionary<string, object>)abNameAssetsTab[kvp.Key];
                    Dictionary<string, string> info = new Dictionary<string, string>();
                    foreach (var infoItem in oneAbInfo)
                    {
                        info.Add(infoItem.Key, JsonHelper.GetJsonStr(infoItem.Value));
                    }
                    filterResultDic1.Add(kvp.Key, info);
                }
            }

            foreach (var item in abSettingsDic)
            {
                string prefabDir = item.Key;
                Dictionary<string, object> cfgArgs = (Dictionary<string, object>)item.Value;
                string includeRegex = JsonHelper.GetJsonStr(cfgArgs["includeRegex"]);
                int memMinSize = JsonHelper.GetJsonInt(cfgArgs["memMinSize"]);
                int maxCount = JsonHelper.GetJsonInt(cfgArgs["maxCount"]);
                float abMaxSize = JsonHelper.GetJsonFloat(cfgArgs["abMaxSize"]);
                string ignoreRegex = cfgArgs.ContainsKey("ignoreRegex") ? JsonHelper.GetJsonStr(cfgArgs["ignoreRegex"]) : string.Empty;
                var sizeTab = BuildOne(prefabDir, includeRegex, memMinSize, maxCount, ignoreRegex);
                filterResultDic[prefabDir] = sizeTab;
                List<Dictionary<string, string>> abInfoList = new List<Dictionary<string, string>>();
                Dictionary<string, string> texItem = new Dictionary<string, string>();
                float abSize = 0f;
                float saveSize = 0f;
                List<string> texPathes = new List<string>(sizeTab.Keys);
                //移除已经在配置中的assetName
                foreach (var assetName in assetNameInPreResult)
                {
                    texPathes.Remove(assetName);
                    // Debug.Log($"Remove assetName:{assetName}");
                }
                texPathes.Sort();
                foreach (var texPath in texPathes)
                {
                    string[] texInfo = sizeTab[texPath];
                    string sizeStr = texInfo[texInfo.Length - 1];
                    string[] sizeStrArr = sizeStr.Split(':');
                    float sizeFloat = JsonHelper.GetJsonFloat(sizeStrArr[0]);
                    int refCount = JsonHelper.GetJsonInt(sizeStrArr[1]);
                    abSize += sizeFloat;
                    saveSize += (refCount - 1) * sizeFloat;
                    texItem.Add(texPath, sizeStr);
                    if (abSize > abMaxSize)
                    {
                        abInfoList.Add(texItem);
                        abSize = 0f;
                        texItem = new Dictionary<string, string>();
                    }
                }
                if (texItem.Count > 0)
                {
                    abInfoList.Add(texItem);
                }
                int maxIndex = dirAbMaxIndexTab.ContainsKey(prefabDir) ? dirAbMaxIndexTab[prefabDir] + 1 : 0;
                for (int idx = 0; idx < abInfoList.Count; idx++)
                {
                    filterResultDic1[prefabDir + "_" + (idx + maxIndex)] = abInfoList[idx];
                }
                Debug.Log($"prefabDir:{prefabDir} save size:{saveSize / 1024.0f}MB!");
            }

            string refTabJsonTest = JsonConvert.SerializeObject(filterResultDic, Formatting.Indented);
            FileHelper.WriteTextToPath(abCommonResultTestPath, refTabJsonTest);
            string refTabJson = JsonConvert.SerializeObject(filterResultDic1, Formatting.Indented);
            FileHelper.WriteTextToPath(abCommonResultPath, refTabJson);
            // EditorUtility.ClearProgressBar();
            Debug.Log("FilterCommonAbTool.Build finish!");
        }

        private static Dictionary<string, string[]> BuildOne(string prefabDir, string inRegexStr, int minMemSize, int maxCount, string igRegexStr)
        {
            Regex includeRegex = new Regex(inRegexStr);
            Regex ignoreRegex = string.IsNullOrEmpty(igRegexStr) ? null : new Regex(igRegexStr);

            string[] prefabFiles = Directory.GetFiles(prefabDir, "*.prefab", SearchOption.AllDirectories);
            Dictionary<string, List<string>> texRefTab = new Dictionary<string, List<string>>();
            int idx = 0;
            foreach (var file in prefabFiles)
            {
                string item = FileHelper.GetUnityPath(file);
                string assetPath = EditorUtils.GetPathRelativeToAssets(item);
                string[] allDeps = AssetDatabase.GetDependencies(assetPath);
                foreach (var dep in allDeps)
                {
                    // EditorUtility.DisplayProgressBar("刷新冗余ab配置", "正在扫描构建配置，请稍候！", 1.0f * idx / prefabFiles.Length);
                    if (!includeRegex.IsMatch(dep))
                    {
                        continue;
                    }
                    if (null != ignoreRegex && ignoreRegex.IsMatch(dep))
                    {
                        continue;
                    }
                    if (texRefTab.ContainsKey(dep))
                    {
                        texRefTab[dep].Add(item);
                    }
                    else
                    {
                        texRefTab[dep] = new List<string>();
                        texRefTab[dep].Add(item);
                    }
                }
            }

            List<TexSortItem> allItems = new List<TexSortItem>();
            foreach (var item in texRefTab)
            {
                if (item.Value.Count > 1)
                {
                    allItems.Add(new TexSortItem(item.Key, item.Value.Count));
                }
            }
            TexSortItem[] allSortedItem = allItems.ToArray();
            System.Array.Sort(allSortedItem);
            Dictionary<string, string[]> sizeTab = new Dictionary<string, string[]>();
            foreach (var item in allSortedItem)
            {
                if (item.memorySize > minMemSize)
                {
                    if (sizeTab.Count >= maxCount)
                    {
                        break;
                    }
                    texRefTab[item.assetPath].Add($"{item.memorySize}:{item.refCount}:{item.packSize}");
                    sizeTab.Add(item.assetPath, texRefTab[item.assetPath].ToArray());
                }
            }

            return sizeTab;
        }
    }
    public class TexSortItem : IComparable<TexSortItem>
    {
        public string assetPath;
        public int refCount;
        public float packSize;
        public float memorySize;

        public TexSortItem(string path, int count)
        {
            assetPath = path;
            refCount = count;

            Texture2D tex2D = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
            long memSize = EditorUtils.GetTextureStorageSize(tex2D);
            // UnityEngine.Debug.Log("assetPath = " + assetPath + " memSize = " + memSize + " FormatBytes = " + EditorUtility.FormatBytes(memSize));
            memorySize = memSize / 1024.0f;
            packSize = memSize / 1024.0f * count;
        }

        public int CompareTo(TexSortItem b)
        {
            if (packSize > b.packSize) return -1;
            if (packSize < b.packSize) return 1;
            return 0;
        }
    }
}